import re
import os
import sys
from robot.errors import DataError
from rsa.util.robot_utilities import open_file, merge, to_robot_var

class VariableLoader(object):

    def get_variables(self, directory, file, prefix=""):
        # N.B. _as_ is a dummy variable; we don't care what it contains,
        # it's just there to make the usage read better
        # (eg: get_variables foo as bar)
        variables = []
        try:
            dot = file.rfind(".")
            extension = file[dot + 1:]
            if(extension == "py"):
                variables = self.get_python_variables(directory, file, prefix)
            if(extension == "js"):
                variables = self.get_javascript_variables(directory, file, prefix)
            if(extension == "csv"):
                variables = self.get_csv_variables(directory, file, prefix)
        except Exception, ex:
            raise DataError(ex)
        return variables
        
    def get_python_variables(self, directory, file, prefix):
        vars = []
        file = open_file(directory, file)
        for line in file:
            if(line.find("=") != -1 or line.find("\":") != -1):
                var = to_robot_var(line) 
                vars.append(var)
        file.close()
        return vars
    
    def get_javascript_variables(self, directory, file, prefix):
        vars = []
        path = merge(directory, file)
        dict = LocatorDict(path, prefix)
        for key in dict:
            vars.append(key.replace(".precedence",""))
        return vars
    
    def get_csv_variables(self, directory, file, prefix):
        vars = []
        file = open_file(directory, file)
        header = file.readline()
        header = header.replace("\n", "")
        header_vars = header.split(",")
        end_of_file = False
        while not end_of_file :
            line = file.readline()
            if not line or line.find(",") == -1:
                end_of_file = True
            else:
                var_name = line[:line.index(",")]
                common = prefix + "." + var_name + "."
                for i in range(1, len(header_vars)):
                    vars.append(common  + header_vars[i])
        file.close()
        return vars    
    
class LocatorDict(dict):
    
    def __init__(self, path, prefix=None):
        dict.__init__(self)
        self._prefix = prefix
        self.load_file(path)

    def load_file(self, path):
        file = self.find_file(path)
        if not file:
            raise DataError("unable to locate mapping file '%s'" % path)

        try:
            f = open(file, "r")
            data = f.read()
        except Exception, e:
            raise DataError("error reading mapping file '%s': %s" % (path, str(e)))

        try:
            # We're parsing javascript, which mostly contains a json definition,
            # which happens to have the same string representation as a valid 
            # python dict. We need to find the start and end of the data and
            # ignore a little javascript cruft. This regex assumes that the
            # opening and closing curly braces are on lines by themselves.
            #
            # why not use a decoder like simplejson? Because this code
            # is likely running in jython, which is stuck in the dark
            # ages. Hopefully that will change soon.
            m = re.search('^(\{.*^\});$', data, re.M | re.DOTALL)

            if m:
                # the data may have embedded javascript comments. Gotta strip
                # them out.
                data = re.sub("/\*.*?\*/", "", m.groups()[0])

                SPLIT_LIMIT = 50000
                while len(data) > SPLIT_LIMIT:
                    split_index = data.find("},", SPLIT_LIMIT)
                    if split_index == -1:
                        break
                    data_part = data[:split_index + 1] + '}'
                    data = '{' + data[split_index + 2:]
                    d = eval(data_part)
                    self.flatten(d, self._prefix)

                d = eval(data)
                self.flatten(d, self._prefix)
                
        except Exception, e:
            raise DataError("error parsing mapping file '%s': %s" % (path, str(e)))

    def find_file(self, path):
        """Look in pwd, then in PYTHONPATH, for the given file"""
        if os.path.exists(path):
            return path
        else:
            for dir in sys.path:
                file = os.path.abspath(os.path.join(dir, path))
                if os.path.exists(file):
                    return file
        return None

    def flatten(self, object, prefix=None):
        for key, value in object.iteritems():
            name = key
            if prefix:
                name = prefix + "." + key
            if isinstance(value, dict):
                # a nested dict
                self.flatten(value, name)
            else:
                dict.__setitem__(self, name, value[0])
                if len(value) > 1:
                    dict.__setitem__(self, name + ".precedence", value[1])
                else:
                    dict.__setitem__(self, name + ".precedence", 0)